package org.huang.spock.spring

import org.huang.spock.spring.bo.Dept
import org.huang.spock.spring.dao.DeptAnnoMapper
import org.huang.spock.spring.dao.PersonAnnoMapper
import org.huang.spock.spring.dto.DeptPersonDTO
import org.huang.spock.spring.param.exception.BizException
import org.huang.spock.spring.param.QueryDeptPageParam
import org.huang.spock.spring.service.DemoService
import org.huang.spock.spring.util.DateUtil
import org.mockito.Mockito
import spock.lang.Ignore
import spock.lang.IgnoreRest
import spock.lang.Specification
import spock.lang.Timeout

import java.util.concurrent.TimeUnit


class DemoServiceMockTest extends Specification {

    def deptAnnoMapper = Mock(DeptAnnoMapper)
    def personAnnoMapper = Mock(PersonAnnoMapper)
    def demoService = new DemoService(deptAnnoMapper: deptAnnoMapper, personAnnoMapper: personAnnoMapper)

    /**
     * case : Mock deptAnnoMapper,personAnnoMapper
     */
//    @Ignore
    def "test getByDeptId "() {
        given: "mock相关的数据"
        deptAnnoMapper.getById(_) >> new Dept(code: "1", name: "xx")
        personAnnoMapper.listByDeptId(_) >> []
        when: "执行测试方法"
        DeptPersonDTO result = demoService.getByDeptId(1)
        then: "断言测试结果"
        with(result) {
            dept == new Dept(code: "1", name: "xx")
            persons == []
        }
    }

    /**
     * case : 静态方法mock
     */
//    @IgnoreRest
    def "test getByDeptId mockStatic"() {
        given: "mock相关的数据"
        deptAnnoMapper.getById(_) >> new Dept(code: "1", name: "xx")
        personAnnoMapper.listByDeptId(_) >> []
        //static方法mock
        def mockStatic = Mockito.mockStatic(DateUtil)
        mockStatic.when(DateUtil::getNow()).thenReturn("2022-01-01 08:00:00")
        when: "执行测试方法"
        DeptPersonDTO result = demoService.getByDeptId(1)
        then: "断言测试结果"
        with(result) {
            date == '2022-01-01 08:00:00'
            dept == new Dept(code: "1", name: "xx")
            persons == []
        }
    }

    /**
     * case : 异常case，和正常case 写在一起的方法
     */
    @Timeout(value = 1, unit=TimeUnit.SECONDS)
    def "test getByDeptId exception and normal"() {
        given: "mock相关的数据"
        deptAnnoMapper.getById(_) >> dept
        personAnnoMapper.listByDeptId(_) >> []
        when: "执行测试方法"
        DeptPersonDTO result = demoService.getByDeptId(1)
        //这里不管怎样，都抛出异常
        throw new BizException(200, 'Success')
        then: "断言测试结果"
        def exception = thrown(expectedException)
        exception.code == expectedCode
        exception.message == expectedMessage

        where:
        dept       || expectedException | expectedCode | expectedMessage
        null       || BizException      | 10000        | '部门不存在'
        new Dept() || BizException      | 200          | 'Success'
    }

    /**
     * case : 调用多次，顺序Mock
     */
    def "test listDeptByCodes"() {
        given:
        //mock多次返回值，第一次调用返回null，第二次调用返回,new Dept(code: "1", name: "name1")，依次类推
        //如果调用次数超过了mock的次数，后续的调用返回最后依次mock的结果
        deptAnnoMapper.getOne(_) >>> [null, new Dept(code: "1", name: "name1"), new Dept(code: "2", name: "name2")]
        //第二种写法
        deptAnnoMapper.getOne(_) >> null >> new Dept(code: "1", name: "name1")
        expect: "断言测试结果"
        demoService.listDeptByCodes(codes) == expectedResult
        where: "case"
        codes                || expectedResult
        null                 || []
        ["1"]                || [null]
        ["1", "2"]           || [null, new Dept(code: "1", name: "name1")]
        ["1", "2", "3"]      || [null, new Dept(code: "1", name: "name1"), new Dept(code: "2", name: "name2")]
        ["1", "2", "3", "4"] || [null, new Dept(code: "1", name: "name1"), new Dept(code: "2", name: "name2"), new Dept(code: "2", name: "name2")]
    }

    /**
     * case : 根据入参计算,Mock返回值
     */
    def "test listDeptPage"() {
        given:
        //第一页有数据，之后的页面没有数据 mock
        deptAnnoMapper.listPaged(_) >> { QueryDeptPageParam param -> param.page == 1 ? [new Dept(code: "1", name: "name1"), new Dept(code: "2", name: "name2")] : [] }

        expect: "断言测试结果"
        demoService.listDeptPage(new QueryDeptPageParam(page: page, pageSize: 10)) == expectedResult

        where: "case"
        page || expectedResult
        1    || [new Dept(code: "1", name: "name1"), new Dept(code: "2", name: "name2")]
        2    || []
        3    || []
    }

    /**
     * case : Mock 异常
     */
    def "test listDeptPage throw exception"() {
        given:
        //mock 抛出异常
        deptAnnoMapper.listPaged(_) >> { throw new BizException(500, 'error!!!') }
        when:
        demoService.listDeptPage(new QueryDeptPageParam(page: 1, pageSize: 10))
        then:
        def exception = thrown(BizException)
        with(exception) {
            code == 500
            message == 'error!!!'
        }
    }

    /**
     * case : 通配符mock
     */
    def "test queryDeptPerson "(){
        given:
        //多个参数的mock通配符
        deptAnnoMapper.getParam(*_) >> new Dept(id:1,code: "1", name: "name1")
        personAnnoMapper.listByIds(_) >> []
        when:
        def result = demoService.queryDeptPerson(1,'name','0100', [1,2,3])
        then:
        with(result) {
            dept == new Dept(id:1,code: "1", name: "name1")
            persons == []
        }
    }



}